package cn.wubo.sqlparser;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.calcite.config.Lex;
import org.apache.calcite.sql.*;
import org.apache.calcite.sql.parser.SqlParser;
import org.apache.calcite.sql.util.SqlBasicVisitor;

@Slf4j
public class CalciteParser {

    public static void parser(String sql) throws Exception {
        SqlNode sqlNode = SqlParser.create(sql, SqlParser.config().withLex(Lex.MYSQL)).parseQuery();
        sqlNode.accept(new SqlBasicVisitor<String>() {
            @SneakyThrows
            public String visit(SqlCall call) {
                if (call.getKind().equals(SqlKind.SELECT)) {
                    SqlSelect select = (SqlSelect) call;
                    select.getSelectList().forEach(colum -> {
                        if (SqlKind.AS.equals(colum.getKind())) {
                            SqlBasicCall basicCall = (SqlBasicCall) colum;
                            log.debug("to: column[{}] as[{}]", basicCall.getOperandList().get(0).toString(), basicCall.getOperandList().get(1).toString());
                        } else if (SqlKind.IDENTIFIER.equals(colum.getKind())) {
                            log.debug("to: column[{}]", colum);
                        }
                    });
                    select.getFrom().accept(new SqlBasicVisitor<String>() {
                        @Override
                        public String visit(SqlCall call) {
                            if (call.getKind().equals(SqlKind.JOIN)) {
                                SqlJoin join = (SqlJoin) call;
                                log.debug("to: join.getRight[{}] join.getCondition[{}]", join.getRight().toString(), join.getCondition().toString());
                                if (!join.getLeft().getKind().equals(SqlKind.JOIN)) {
                                    log.info("to: join.getLeft[{}]", join.getLeft().toString());
                                }
                            }
                            return call.getOperator().acceptCall(this, call);
                        }
                    });
                    select.getWhere().accept(new SqlBasicVisitor<String>() {
                        @Override
                        public String visit(SqlCall call) {
                            if (call.getKind().equals(SqlKind.AND) || call.getKind().equals(SqlKind.OR)) {
                                SqlBasicCall sql = (SqlBasicCall) call;
                                SqlBasicCall left = (SqlBasicCall) sql.getOperandList().get(0);
                                SqlBasicCall right = (SqlBasicCall) sql.getOperandList().get(1);
                                log.debug("to: kind[{}] right[{}]", sql.getKind(), right);
                                if (!left.getKind().equals(SqlKind.AND) && !left.getKind().equals(SqlKind.OR)) {
                                    log.debug("to: left[{}]", left);
                                }
                            }
                            return call.getOperator().acceptCall(this, call);
                        }
                    });

                    log.debug("to: old_sql[{}]", select);
                    SqlNode condition = SqlParser.create("1=1").parseExpression();
                    SqlNode where = SqlUtil.andExpressions(select.getWhere(), condition);
                    select.setWhere(where);
                    log.debug("to: new_sql[{}]", select);
                }
                return call.getOperator().acceptCall(this, call);
            }
        });
    }
}
